
import sys, time
import mpdiface
from mpdiface import Attrs
import playmgr
import conf
from conf import *
import widgets
from draw import *

import readline, curses, signal, termios, os, struct
from curses import A_NORMAL, A_BOLD
from fcntl import ioctl

# maybe move this global stuff
screen = None
nowplaying = None
if len(sys.argv) > 1:
    host = sys.argv[1]
else:
    host = "127.0.0.1"
mpd = mpdiface.Client(host)
controller = None
widget = None

# From http://groups.google.com/group/comp.lang.python/msg/70fa595d97e90040
def getheightwidth():
    try:
        return int(os.environ["LINES"]), int(os.environ["COLUMNS"])
    except KeyError:
        height, width = struct.unpack(
            "hhhh", ioctl(0, termios.TIOCGWINSZ ,"\000"*8))[0:2]
        if not height: return 25, 80
        return height, width

# SIGWINCH stuff
def sigwinch(sig, frame):
    #curses.endwin()
    #screen = curses.initscr()
    conf.screen.clear()
    conf.screen.refresh()
    conf.SCREEN_H, conf.SCREEN_W = getheightwidth()
    conf.L_KEY_HELP = conf.SCREEN_H
signal.signal(signal.SIGWINCH, sigwinch)


# regular stuff
def redraw_labels(status):
    global widget
    conf.screen.addstr(0, 0, "connected to mpd %s on %s" % (mpd.mpd_version, host))
    conf.screen.addstr(4, centrex(M_NOW_PLAYING), M_NOW_PLAYING)
    clrline(L_KEY_HELP)
    if widget is None:
        if status.state == "pause":
            pause_or_unpause = "unpause"
        else:
            pause_or_unpause = "pause"
        if status.state == "stop":
            stop_or_play = "play"
        else:
            stop_or_play = "stop"
        normcentred(L_KEY_HELP, "Enter: search, < >: skip, p: %s, s: %s, d: delete next" % (pause_or_unpause, stop_or_play))
    else:
        normcentred(L_KEY_HELP, "a-z: type search string, Enter: queue as next, .: add to end, !: play now")

def current_song():
    status = Attrs(mpd.status())
    if status.state != "play":
        return None
    return Attrs(mpd.currentsong())

def update_nowplaying(status):
    global nowplaying
    song = controller.currentsong()
    conf.screen.addstr(L_QUEUE_INFO, conf.SCREEN_W-20, "%s/%s" % (int(status.song)+1, status.playlistlength), A_NORMAL)
    conf.screen.addstr(L_QUEUE_INFO, 20, "%s%%" % status.volume, A_NORMAL)
    clrline(L_TITLE)
    clrline(L_ARTIST)
    clrline(L_ALBUM)
    if song is None:
        clrline(L_BY)
        clrline(L_FROM)
        boldcentred(L_TITLE, M_NOTHING)
    elif nowplaying is None or nowplaying != song:
        if "artist" in song.d and "title" in song.d:
            boldcentred(L_TITLE, song.title)
            if SHOW_BY: normcentred(L_BY, M_BY)
            boldcentred(L_ARTIST, song.artist)
            if "album" in song.d:
                if SHOW_FROM: normcentred(L_FROM, M_FROM)
                if SHOW_ALBUM: boldcentred(L_ALBUM, song.album)
            else:
                clrline(L_FROM)
        else:
            clrline(L_BY)
            clrline(L_FROM)
            boldcentred(L_TITLE, song.file)
        nowplaying = song

    next = controller.nextsong()
    clrline(L_NEXT_SONG)
    if next is not None:
        try:
            pcentred(L_NEXT_SONG, (A_NORMAL, "Next: " if status.state == 'play' else ({'pause':"Paused on: ", 'stop':"Stopped on: "})[status.state]), (A_BOLD, next.artist), (A_NORMAL, " - "), (A_BOLD, next.title))
        except AttributeError:
            pcentred(L_NEXT_SONG, (A_NORMAL, "Next: " if status.state == 'play' else ({'pause':"Paused on: ", 'stop':"Stopped on: "})[status.state]), (A_BOLD, next.file))


def mpdexit():
    mpd.close()
    sys.exit()

# input
def dispatch(key):
    global widget, controller
    nowplaying_dirty = True
    def search(text):
        global controller
        return controller.search(text)
    def selectnow(song):
        controller.playnow(song)
    def selectnext(song):
        controller.playnext(song)
    def selectlater(song):
        return controller.playlater(song)

    if widget is None:
        status = controller.status()
        if key == ord('Q'):
            mpdexit()
        elif key == conf.KEY_ENTER:
            widget = widgets.SearchBox(L_SEARCH_BOX, search)
            widget.onselectnow = selectnow
            widget.onselectnext = selectnext
            widget.onselectlater = selectlater
        elif key == ord('>'):
            controller.next()
        elif key == ord('<'):
            controller.prev()
        elif key == ord('p'):
            controller.pause()
            conf.screen.refresh()
        elif key == ord('s'):
            if status.state == 'stop':
                controller.play()
            else:
                controller.stop()
        elif key == ord('d'):
            controller.delnext()
        elif key == ord('='):
            state = controller.status()
            vol = int(state.volume)
            new_vol = vol + 5
            if new_vol > 100:
                new_vol = 100
            if new_vol != vol:
                nowplaying_needs_update = True
            controller.setvol(new_vol)
        elif key == ord('-'):
            state = controller.status()
            vol = int(state.volume)
            new_vol = vol - 5
            if new_vol < 0:
                new_vol = 0
            if new_vol != vol:
                nowplaying_needs_update = True
            controller.setvol(new_vol)
    elif widget is not None:
        nowplaying_dirty = key in (conf.KEY_ENTER, ord('.'), ord('!'), conf.KEY_BACKSPACE, conf.KEY_ESCAPE)
        if key == conf.KEY_ESCAPE:
            widget.blank()
            widget = None
        else:
            if key == conf.KEY_BACKSPACE and not widget.text:
                widget.blank()
                widget = None
            else:
                if widget.onkeypress(key):
                    widget.blank()
                    widget = None
    return nowplaying_dirty


# main stuff
def main(scr):
    global screen, controller
    conf.screen = scr
    conf.SCREEN_H, conf.SCREEN_W = getheightwidth()
    conf.L_KEY_HELP = conf.SCREEN_H
    curses.curs_set(0)
    conf.screen.nodelay(1)
    conf.screen.clear()
    normcentred(conf.SCREEN_H/2-1, "Retrieving library information")
    conf.screen.refresh()
    controller = playmgr.Controller(mpd)
    conf.screen.clear()
    while 1:
        nowplaying_needs_update = True
        for i in range(KEY_POLL_RATE):
            key = conf.screen.getch()
            if key == -1:
                time.sleep(2.9/KEY_POLL_RATE)
                continue
            else:
                clrline(L_DJ_MESSAGE)
                nowplaying_needs_update = dispatch(key)
                break
        else:
            clrline(L_DJ_MESSAGE)

        if nowplaying_needs_update:
            # do stuff that updates the screen
            controller.tick()
            status = controller.status()
            redraw_labels(status)
            update_nowplaying(status)
            if widget is not None:
                #widget.tick()
                widget.redraw()

        # finished updating screen here
        conf.screen.refresh()
        time.sleep(0.1)

# stuff
if __name__ == "__main__":
    import socket
    try:
        status = mpd.status()
        print "Successfully contacted MPD: state=%(state)s, %(playlistlength)s in playlist" % status
        time.sleep(0.5)
        while 1:
            curses.initscr()
            curses.start_color()
            curses.init_pair(1, curses.COLOR_RED, curses.COLOR_BLACK)
            try:
                curses.wrapper(main)
            except curses.error, reason:
                print \
"""Curses: %s
Most likely the window is too small. Try increasing the size of the
xterm to allow at least 28 lines.""" % reason
                # (Or alternatively, edit the line numbers in conf.py and the
                # height of the search box in widgets.py so it fits)
                sys.exit(2)
    except KeyboardInterrupt:
        sys.stdout.write("\n")
        sys.exit()
    except socket.error, reason:
        print "Couldn't contact MPD or socket trouble controlling MPD"
        print "socket error %s" % reason
        sys.exit(3)
    except mpdiface.ConnectionRetryError:
        print "Connection dropped during execution of an MPD command"
        print "retried %d times without success" % mpd.__max_connection_retries
        sys.exit(4)
